
#ifndef DEBUGRENDER_H_
#define DEBUGRENDER_H_

#include "Window.h"
#include "Entity.h"
#include "ConvexPolygon.h"
#include "Constraint.h"
#include "PulleyJoint.h"
#include "Collider.h"

using namespace p2;

static void renderConstraint(boost::shared_ptr<Renderer> renderer, Constraint* constraint);
static void renderEntity(boost::shared_ptr<Renderer> renderer, Entity* entity);
static void renderContacts(boost::shared_ptr<Renderer> renderer, Collider& collider);
static void renderGrid(boost::shared_ptr<Renderer> renderer, real worldWidth, real worldHeight);

//#ifdef DEBUG
void renderConstraint(boost::shared_ptr<Renderer> renderer, Constraint* constraint)
{
	Vector2<real> xa0(constraint->getWorldAnchor0());
	RenderVertexVC const vxa0[] = {
		{ { xa0.X()-1, xa0.Y()-1 }, { 1.f, 0.f, 0.f, 1.f } },
		{ { xa0.X()-1, xa0.Y()+1 }, { 1.f, 0.f, 0.f, 1.f } },
		{ { xa0.X()+1, xa0.Y()+1 }, { 1.f, 0.f, 0.f, 1.f } },
		{ { xa0.X()+1, xa0.Y()-1 }, { 1.f, 0.f, 0.f, 1.f } }
	};
	renderer->draw(GL_LINE_LOOP, vxa0, 4);

	PulleyJoint* pj = PulleyJoint::cast(constraint);
	if (pj) {
		Vector2<real> xpa(pj->getWorldPulleyAnchor0());
		RenderVertexVC const vxpa[] = {
			{ { xpa.X()-1, xpa.Y()-1 }, { 0.f, 1.f, 0.f, 1.f } },
			{ { xpa.X()-1, xpa.Y()+1 }, { 0.f, 1.f, 0.f, 1.f } },
			{ { xpa.X()+1, xpa.Y()+1 }, { 0.f, 1.f, 0.f, 1.f } },
			{ { xpa.X()+1, xpa.Y()-1 }, { 0.f, 1.f, 0.f, 1.f } }
		};
		renderer->draw(GL_LINE_LOOP, vxpa, 4);
		Vector2<real> xa0(pj->getWorldAnchor0());
		RenderVertexVC const vxa0[] = {
			{ { xa0.X()-1, xa0.Y()-1 }, { 1.f, 0.f, 0.f, 1.f } },
			{ { xa0.X()-1, xa0.Y()+1 }, { 1.f, 0.f, 0.f, 1.f } },
			{ { xa0.X()+1, xa0.Y()+1 }, { 1.f, 0.f, 0.f, 1.f } },
			{ { xa0.X()+1, xa0.Y()-1 }, { 1.f, 0.f, 0.f, 1.f } }
		};
		renderer->draw(GL_LINE_LOOP, vxa0, 4);
		RenderVertexVC const vpaa0[] = {
			{ { xpa.X(), xpa.Y() }, { 1.f, 0.f, 0.f, 1.f } },
			{ { xa0.X(), xa0.Y() }, { 0.f, 1.f, 0.f, 1.f } }
		};
		renderer->draw(GL_LINES, vpaa0, 2);

		Vector2<real> xpb(pj->getWorldPulleyAnchor1());
		RenderVertexVC const vxpb[] = {
			{ { xpb.X()-1, xpb.Y()-1 }, { 0.f, 1.f, 0.f, 1.f } },
			{ { xpb.X()-1, xpb.Y()+1 }, { 0.f, 1.f, 0.f, 1.f } },
			{ { xpb.X()+1, xpb.Y()+1 }, { 0.f, 1.f, 0.f, 1.f } },
			{ { xpb.X()+1, xpb.Y()-1 }, { 0.f, 1.f, 0.f, 1.f } }
		};
		renderer->draw(GL_LINE_LOOP, vxpb, 4);
		Vector2<real> xa1(pj->getWorldAnchor1());
		RenderVertexVC const vxa1[] = {
			{ { xa1.X()-1, xa1.Y()-1 }, { 1.f, 0.f, 0.f, 1.f } },
			{ { xa1.X()-1, xa1.Y()+1 }, { 1.f, 0.f, 0.f, 1.f } },
			{ { xa1.X()+1, xa1.Y()+1 }, { 1.f, 0.f, 0.f, 1.f } },
			{ { xa1.X()+1, xa1.Y()-1 }, { 1.f, 0.f, 0.f, 1.f } }
		};
		renderer->draw(GL_LINE_LOOP, vxa1, 4);
		RenderVertexVC const vpaa1[] = {
			{ { xa1.X(), xa1.Y() }, { 1.f, 0.f, 0.f, 1.f } },
			{ { xpb.X(), xpb.Y() }, { 0.f, 1.f, 0.f, 1.f } }
		};
		renderer->draw(GL_LINES, vpaa1, 2);
	} else {
		TrackPinJoint* sp = TrackPinJoint::cast(constraint);
		if (sp) {
			Vector2<real> xl0, xl1;
			sp->getWorldLine(xl0, xl1);
			RenderVertexVC const va0la[] = {
				{ { xl0.X(), xl0.Y() }, { 0.f, 0.f, 1.f, 1.f } },
				{ { xl1.X(), xl1.Y() }, { 0.f, 0.f, 1.f, 1.f } }
			};
			renderer->draw(GL_LINES, va0la, 2);
		} else {
			Vector2<real> xa1(constraint->getWorldAnchor1());
			RenderVertexVC const vxa1[] = {
				{ { xa1.X()-1, xa1.Y()-1 }, { 0.f, 1.f, 0.f, 1.f } },
				{ { xa1.X()-1, xa1.Y()+1 }, { 0.f, 1.f, 0.f, 1.f } },
				{ { xa1.X()+1, xa1.Y()+1 }, { 0.f, 1.f, 0.f, 1.f } },
				{ { xa1.X()+1, xa1.Y()-1 }, { 0.f, 1.f, 0.f, 1.f } }
			};
			RenderVertexVC const va0a1[] = {
				{ { xa0.X(), xa0.Y() }, { 1.f, 0.f, 0.f, 1.f } },
				{ { xa1.X(), xa1.Y() }, { 0.f, 1.f, 0.f, 1.f } }
			};
			renderer->draw(GL_LINE_LOOP, vxa1, 4);
			renderer->draw(GL_LINES, va0a1, 2);
		}
	}
}

void renderEntity(boost::shared_ptr<Renderer> renderer, Entity* entity)
{
	foreach (Element* element, entity->getElements()) {
		ConvexPolygon* ecp = ConvexPolygon::cast(element);
		if (ecp) {
			uint32 sizeA = ecp->getWorldVertices().size();
			for (uint32 i = 0; i < sizeA; i++) {
				uint32 wV0i = i;
				uint32 wV1i = (i + 1) % sizeA;
				Vector2<real> &V0 = ecp->getWorldVertices()[wV0i];
				Vector2<real> &V1 = ecp->getWorldVertices()[wV1i];
				RenderVertexVC const v[] = {
					{ { V0[0], V0[1] }, { 1.f, 1.f, 1.f, 1.f } },
					{ { V1[0], V1[1] }, { 1.f, 1.f, 1.f, 1.f } }
				};
				renderer->draw(GL_LINES, v, 2);
			}
//			Vector2<real> const& xecp(ecp->getWorldPosition());
//			std::vector<Vector2<real> >::iterator iter = ecp->getWorldNormals().begin();
//			for (; iter != ecp->getWorldNormals().end(); ++iter) {
//				Vector2<real> const& n = (*iter);
//				RenderVertexVC const vxecn[] = {
//					{ { xecp[0], xecp[1] }, { 1.f, 1.f, 1.f, 1.f } },
//					{ { xecp[0]+n[0]*10, xecp[1]+n[1]*10 }, { 1.f, 1.f, 1.f, 1.f } }
//				};
//				renderer->draw(GL_LINES, vxecn, 2);
//			}
			Aabb2<real> const& maabb(element->getMotionBounds());
			RenderVertexVC const vmaabb[] = {
				{ { maabb.min().X(), maabb.min().Y() }, { 1.f, 0.f, 0.f, 1.f } },
				{ { maabb.min().X(), maabb.max().Y() }, { 1.f, 0.f, 0.f, 1.f } },
				{ { maabb.max().X(), maabb.max().Y() }, { 1.f, 0.f, 0.f, 1.f } },
				{ { maabb.max().X(), maabb.min().Y() }, { 1.f, 0.f, 0.f, 1.f } }
			};
			renderer->draw(GL_LINE_LOOP, vmaabb, 4);
			Aabb2<real> const& waabb(element->getWorldBounds());
			RenderVertexVC const vwaabb[] = {
				{ { waabb.min().X(), waabb.min().Y() }, { 0.5f, 0.5f, 0.5f, 1.f } },
				{ { waabb.min().X(), waabb.max().Y() }, { 0.5f, 0.5f, 0.5f, 1.f } },
				{ { waabb.max().X(), waabb.max().Y() }, { 0.5f, 0.5f, 0.5f, 1.f } },
				{ { waabb.max().X(), waabb.min().Y() }, { 0.5f, 0.5f, 0.5f, 1.f } }
			};
			renderer->draw(GL_LINE_LOOP, vwaabb, 4);
		} else {
			Disc* ed = Disc::cast(element);
			if (ed) {
				real radius = ed->getRadius();
//				for () {
//
//				}
			}
		}
	}
	Vector2<real> xcom(entity->getX());
	RenderVertexVC const vxcom[] = {
		{ { xcom.X()-10, xcom.Y() }, { 0.f, 0.f, 1.f, 1.f } },
		{ { xcom.X()+10, xcom.Y() }, { 0.f, 0.f, 1.f, 1.f } },
		{ { xcom.X(), xcom.Y()-10 }, { 0.f, 0.f, 1.f, 1.f } },
		{ { xcom.X(), xcom.Y()+10 }, { 0.f, 0.f, 1.f, 1.f } }
	};
	renderer->draw(GL_LINES, vxcom, 4);
}

void renderContacts(boost::shared_ptr<Renderer> renderer, Collider& collider)
{
	Contact::List::iterator iter = collider.getContacts().begin();
	for (; iter != collider.getContacts().end(); ++iter) {
		Contact& contact = (*iter);
		for (uint32 pi = 0; pi < contact._nppb; ++pi) {
			Vector2<real> xa(contact._pa[pi]);// + contact._ra[pi]);
			RenderVertexVC const vxa[] = {
				{ { xa.X()-1, xa.Y()-1 }, { 1.f, 0.f, 0.f, 1.f } },
				{ { xa.X()-1, xa.Y()+1 }, { 1.f, 0.f, 0.f, 1.f } },
				{ { xa.X()+1, xa.Y()+1 }, { 1.f, 0.f, 0.f, 1.f } },
				{ { xa.X()+1, xa.Y()-1 }, { 1.f, 0.f, 0.f, 1.f } }
			};
			renderer->draw(GL_LINE_LOOP, vxa, 4);
			Vector2<real> xb(contact._pb[pi]);// + contact._rb[pi]);
			RenderVertexVC const vxb[] = {
				{ { xb.X()-2, xb.Y()-2 }, { 0.f, 0.f, 1.f, 1.f } },
				{ { xb.X()-2, xb.Y()+2 }, { 0.f, 0.f, 1.f, 1.f } },
				{ { xb.X()+2, xb.Y()+2 }, { 0.f, 0.f, 1.f, 1.f } },
				{ { xb.X()+2, xb.Y()-2 }, { 0.f, 0.f, 1.f, 1.f } }
			};
			renderer->draw(GL_LINE_LOOP, vxb, 4);
		}
	}
}

void renderGrid(boost::shared_ptr<Renderer> renderer, real worldWidth, real worldHeight)
{
	for (real y = 0.f; y < worldHeight; y += 100.f ) {
		for (real x = 0.f; x < worldWidth; x += 100.f ) {
			Vector2<real> xz(x, y);
			RenderVertexVC const vxc[] = {
				{ { xz.X()-5, xz.Y()+0 }, { 0.5f, 0.5f, 0.5f, 1.f } },
				{ { xz.X()+5, xz.Y()+0 }, { 0.5f, 0.5f, 0.5f, 1.f } },
				{ { xz.X()+0, xz.Y()-5 }, { 0.5f, 0.5f, 0.5f, 1.f } },
				{ { xz.X()+0, xz.Y()+5 }, { 0.5f, 0.5f, 0.5f, 1.f } }
			};
			renderer->draw(GL_LINES, vxc, 4);
		}
	}
}
//#endif	//#ifdef DEBUG

#endif	//DEBUGRENDER_H_
